/*
 * Copyright 2020 www.mytijian.com All right reserved. This software is the
 * confidential and proprietary information of www.mytijian.com ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with www.mytijian.com.
 */
package com.mytijian.task.task.step;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.mytijian.base.exception.ErrorInfo;
import com.mytijian.task.enums.TaskTypeEnum;
import com.mytijian.task.model.SubmitTask;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class TaskStepContainer {
    private static Map<TaskTypeEnum, TaskStep> map = new ConcurrentHashMap<>();

    public static void put(TaskTypeEnum taskTypeEnum, TaskStep taskStep) {
        if (map.get(taskTypeEnum) != null) {

            return;
        }
        map.put(taskTypeEnum, taskStep);
    }

    private static TaskStep getTaskStep(TaskTypeEnum taskTypeEnum) {
        return map.get(taskTypeEnum);
    }

    public static <T> ErrorInfo beforeSubmitValidate(SubmitTask<T> submitTask) {
        TaskValidator validator = getTaskStep(submitTask.getTaskTypeEnum()).getTaskValidator();
        if (validator != null) {
            return validator.validate(submitTask);
        }
        return null;
    }

    public static boolean needRetry(TaskTypeEnum taskTypeEnum, Integer currentRetryTimes, Throwable... exceptions) {
        TaskStep taskStep = getTaskStep(taskTypeEnum);
        if (taskStep.getE() == null) {
            return false;
        }
        if (taskStep.getRetryTimes() == null || taskStep.getRetryTimes() == 0) {
            return false;
        }
        if (exceptions == null) {
            return false;
        }
        List<Throwable> list = Lists.newArrayList(exceptions);
        List<Class<? extends Throwable>> classList = new ArrayList<>(list.size());
        for (Throwable throwable : list) {
            if (throwable != null) {
                classList.add(throwable.getClass());
            }
        }
        return taskStep.getRetryTimes() > currentRetryTimes && classList.contains(taskStep.getE().getClass());
    }

    public static <I> void process(TaskTypeEnum taskTypeEnum, I input) {
        TaskStep taskStep = getTaskStep(taskTypeEnum);
        taskStep.getTaskProcess().process(input);
    }

    public static <I> I getProcessValue(TaskTypeEnum taskTypeEnum, String valueJson) {
        Class clazz = (Class) ((ParameterizedType) getTaskStep(taskTypeEnum).getTaskProcess().getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        return (I) JSON.parseObject(valueJson, clazz);
    }

    public static <I> boolean needProcess(TaskTypeEnum taskTypeEnum, I input) {
        TaskStep taskStep = getTaskStep(taskTypeEnum);
        return taskStep.getTaskProcess().needProcess(input);
    }

    public static <O,I> O reader(TaskTypeEnum taskTypeEnum, I input) {
        return (O) getTaskStep(taskTypeEnum).getDataReader().reader(input);
    }
}
